#include "Worker.hh"

USNumber Worker::Count = 0;

Worker::Worker(BlockingQueue* Queue)
{
	State = false;
	
	ResultOf Result;
	Result = setLife(-1);
	checkErrorFV(Result, "Fail setRetirementAge.");
	
	QueueOfTask = Queue;
	checkNullFV(QueueOfTask, "QueueOfTask is NULL.");
	
	TID = 0;
	Working = false;
	
	State = true;
}

ResultOf Worker::work()
{
	if (!State)
	{
		fprintf(stderr, "This instance(%x) is not available.\n", (Number)this);
		return RETURN_ERROR;
	}
	
	if (Working == true)
		return RETURN_OK;
	
	ResultOf Result;
	Result = createThread();
	checkErrorWR(Result, "Fail createThread.");
	
	Working = true;
	return RETURN_OK;
}

ResultOf Worker::setLife(USNumber NumOfWorking)
{
	if (NumOfWorking == 0)
	{
		notifyError(NumOfWorking, "Bad parameter.");
		return RETURN_PARAM_ERROR;
	}
	
	Life = NumOfWorking;
	return RETURN_OK;
}

ResultOf Worker::fetchTask(Task* NewTask)
{
	if (!State)
	{
		fprintf(stderr, "This instance(%x) is not available.\n", (Number)this);
		return RETURN_ERROR;
	}
	
	if (NewTask == NULL)
	{
		notifyError(NewTask, "Bad parameter.");
		return RETURN_PARAM_ERROR;
	}
	
	ResultOf Result;
	Result = QueueOfTask->enqueue((void*)NewTask);
	checkErrorWR(Result, "Fail QueueOfTask->push.");
	
	return RETURN_OK;
}

ResultOf Worker::retire()
{
	if (!State)
	{
		fprintf(stderr, "This instance(%x) is not available.\n", (Number)this);
		return RETURN_ERROR;
	}
	
	if (!Working)
		return RETURN_OK;
	
	Life = 0;
	Working = false;
	
	ResultOf Result;
	Result = finalizeTask();
	checkErrorWR(Result, "Fail finalizeTask.");
	
	Result = waitThread();
	checkErrorWR(Result, "Fail waitThread.");
	
	return RETURN_OK;
}

ResultOf Worker::doWorking()
{
	ResultOf Result;
	Task* AssignedTask;
	
	while (checkRetired())
	{
		Result = QueueOfTask->dequeue((void**)&AssignedTask);
		switch (Result)
		{
			case RETURN_OK:
				break;
			
			case RETURN_BLOCK:
			case RETURN_TIMEOUT:
				return RETURN_OK;
			
			default:
				notifyError(Result, "QueueOfTask->dequeue.");
				return RETURN_ERROR;
		}
		
		if (AssignedTask == NULL)
			continue;
		
		Result = handleTask(AssignedTask);
		checkErrorWR(Result, "Fail handleTask.");
		
		Result = updateLife();
		checkErrorWR(Result, "Fail updateAge.");
	}
	
	return RETURN_OK;
}

ResultOf Worker::handleTask(Task* AssignedTask)
{
	ResultOf Result;
	Result = AssignedTask->perform();
	checkErrorWOR(Result, "Fail AssignedTask->perform.");
		
	delete AssignedTask;
	return RETURN_OK;
}

ResultOf Worker::finalizeTask()
{
	ResultOf Result;
	Result = QueueOfTask->flush();
	checkErrorWR(Result, "Fail QueueOfTask->waitEmpty.");
	
	return RETURN_OK;
}

bool Worker::checkRetired()
{
	return Life > 0;
}

ResultOf Worker::updateLife()
{
	if (Life == 0 || Life == (USNumber)-1)
		return RETURN_OK;
	
	--Life;
	return RETURN_OK;
}

ResultOf Worker::createThread()
{
	ResultOf Result;
	Result = pthread_create(&TID, NULL, ThreadFunc, (void*)this);
	checkErrorWR(Result, "Fail pthread_create.");
	
	return RETURN_OK;
}

 ResultOf Worker::waitThread()
{
	ResultOf Result;
	Result = pthread_join(TID, NULL);
	checkErrorWR(Result, "Fail pthread_join.");
	
	return RETURN_OK;
}

ResultOf Worker::resign()
{
	if (!Working)
		return RETURN_OK;
	
	Working = false;
	
	ResultOf Result;
	Result = pthread_detach(TID);
	checkErrorWR(Result, "Fail pthread_detach.");
	
	return RETURN_OK;
}

void* Worker::ThreadFunc(void* Param)
{
	Worker* This = (Worker*)Param;
	
	ResultOf Result;
// 	Result = This->setAffinity();
// 	checkErrorWOR(Result, "Fail This->setAffinity.");
	
	Result = This->doWorking();
	checkErrorWOR(Result, "Fail This->doWorking.");
	
	Result = This->resign();
	checkErrorWOR(Result, "Fail This->retire.");
	
	return NULL;
}

ResultOf Worker::setAffinity()
{
	// TODO
	// '4' 라는 하드 코딩을 했는데, 나중에 바꾸자.
	++Count;
	
	CPU_ZERO(&ProcessorSet);
	CPU_SET(Count % 4, &ProcessorSet );
	
	ResultOf Result;
	Result = pthread_setaffinity_np(TID, sizeof(ProcessorSet), &ProcessorSet);
	checkErrorWR(Result, "Fail pthread_setaffinity_np.");
	
	return RETURN_OK;
}
